package com.laizhenghua.example.service.impl;

import com.laizhenghua.example.configuration.ExcelConfig;
import com.laizhenghua.example.configuration.QueryParamDTO;
import com.laizhenghua.example.dao.UserDao;
import com.laizhenghua.example.entity.UserEntity;
import com.laizhenghua.example.service.ExcelService;
import com.laizhenghua.example.service.UserService;
import com.laizhenghua.example.utils.XmlParser;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @date: 2022/5/1 18:04
 */
@Service(value = "userService")
public class UserServiceImpl implements UserService {

    private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;

    @Autowired
    private ExcelService excelService;

    @Override
    public Map<String, String> importExcelData(MultipartFile file, QueryParamDTO queryParam) {
        Map<String, String> result = new HashMap<>();
        // 1.获取Excel标题、实体、表字段的映射关系
        ExcelConfig configInfo = XmlParser.getConfigInfo(queryParam.getFilePath(), queryParam.getFileName(), queryParam.getConfigName());
        if (configInfo == null) {
            result.put("error", "导入失败无法找到配置信息！");
            return result;
        }
        // 2.解析Excel数据
        List<Map<String, Cell>> excelData = excelService.resolveExcelData(file);
        if (excelData == null || excelData.size() == 0) {
            result.put("error", "导入失败Excel文件解析失败");
            return result;
        }
        // 3.基于配置文件封装Excel数据(封装成实体)
        List<UserEntity> entityList = excelService.convertEntity(configInfo, excelData, UserEntity.class);
        if (CollectionUtils.isEmpty(entityList)) {
            result.put("error", "获取实体信息失败");
            return result;
        }
        // 4.保存
        int listSize = entityList.size();
        int toIndex = 100;
        for (int i = 0; i < listSize; i += 100) {
            if ((i + 100) > listSize) {
                toIndex = listSize - i;
            }
            // 每次保存100
            List<UserEntity> subList = entityList.subList(i, i + toIndex);
            if (subList.size() > 0) {
                userDao.saveAll(subList);
            }
        }
        result.put("success", String.format("保存成功%s个", listSize));
        return result;
    }

    @Override
    public String exportData(QueryParamDTO queryParam, HttpServletResponse response) {
        // 1.获取xml配置信息
        ExcelConfig configInfo = XmlParser.getConfigInfo(queryParam.getFilePath(), queryParam.getFileName(), queryParam.getConfigName());
        if (configInfo == null) {
            return "导出失败！无法找到[configName=" + queryParam.getConfigName() + "]的配置信息";
        }
        // 2.获取数据库数据
        List<UserEntity> userList = userDao.findAll();
        if (CollectionUtils.isEmpty(userList)) {
            return "导出失败！数据库数据为空";
        }
        // 3.根据配置信息，将Java实体数据写入Excel表里
        File file = new File(configInfo.getName() + ".xlsx");
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error(e);
            }
        }
        FileOutputStream fos = null;
        InputStream inputStream = null;
        try {
            fos = new FileOutputStream(file);
            excelService.writeOutputStreamByConfig(configInfo, userList, fos);
            // 设置 ContentType
            String fileName = URLEncoder.encode(file.getName(), "utf-8");
            response.setContentType("application/octet-stream"); // application/vnd.ms-excel;charset=utf-8
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            // 把文件以流的形式写入
            ServletOutputStream outputStream = response.getOutputStream();
            inputStream = new FileInputStream(file);
            excelService.write(inputStream, outputStream);
            response.getOutputStream().close();
        } catch (IOException e) {
            log.error(e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    log.error(e);
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e);
                }
            }
            file.delete();
        }
        return "导出成功！";
    }
}
